/*
 * sysmo 服务器已被加入监控列表的客户端（节点）信息
 * Copyright (C) 2009  YuLicheng
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.sysmo.server.node;

import java.util.List;
import org.sysmo.db.DatabaseInterface;
import org.sysmo.db.DbClient;
import org.sysmo.server.node.item.Item;
import org.sysmo.server.node.item.ItemNotExistsException;
import org.sysmo.server.util.ChildEventListener;
import org.sysmo.server.util.InstanceNotInitializedException;

/**
 * 
 * 所有已经加入监控列表的的客户端（节点）信息抽象父类。其每个子类实例对应于一个被监控
 * 的节点。此类的实例可表示监控列表中已经连接的和没有连接的客户端节点。
 * <br />
 *
 * 注意：对于节点上监控项的操作应在已连接节点类中实现，对于未连接的节点不提供在线配置
 * 功能。
 * 
 * @author YuLicheng
 */
public abstract class AddedNode extends Node
        implements ChildEventListener<Item> {

    /**
     * 数据库接口客户端节点对象。
     */
    protected DbClient node;

    /**
     * 此构造函数用于保存数据库存储接口，此接口可被各子类使用。在本类中，数据库接口用
     * 于获得监控列表内的所有被监控节点及相应设置。
     *
     * @param stateListener 节点状态回调接口。
     * @param dbInterface 数据库访问接口。
     * @param id 此节点客户端ID。
     * @throws NodeNotExistsException
     */
    public AddedNode(NodeStateChangeListener stateListener,
            DatabaseInterface dbInterface, int id)
            throws NodeNotExistsException {
        super(dbInterface, stateListener);
        this.dbInterface = dbInterface;
        try {
            node = dbInterface.query_ClientTable(id);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (node == null) {
            throw new NodeNotExistsException(id);
        }
    }

    /**
     * 从监控列表中删除当前节点
     * <br />
     *
     * 无论客户端当前是否已连接，都将其从数据库中删除。若客户端已连接则应调用
     * ConnectedNode对象的{@link ConnectedNode#remove()}方法，其会发送相应消息给
     * 客户端，然后调用此方法从数据库中删除数据。若客户端没有连接，则下次连接时将会得
     * 到连接失败消息。同时还将从数据库中删除与此节点相关联的所有配置和监控数据的历史
     * 记录。
     * <br />
     *
     * 当节点被删除后，将调用节点状态回调接口的
     * {@link NodeStateChangeListener#nodeRemoved(AddedNode)}方法通知外部逻辑。
     */
    protected void remove() {
        if (node == null) {
            throw new InstanceNotInitializedException();
        }
        stateListener.nodeRemoved(this);
        try {
            dbInterface.delete_ClientTable(node.cid);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 将当前节点对象设为无效。在使用remove删除此节点后应调用此方法。
     */
    public abstract void invalid();

    /**
     * 设置节点的名称。名称信息不必发送给客户端，仅用于在Web管理页面上查看。
     *
     * @param name 节点新名称。
     */
    public void setName(String name) {
        if (node == null) {
            throw new InstanceNotInitializedException();
        }
        node.name = name;
    }

    /**
     * 获取节点名称。
     *
     * @return 节点名称。
     */
    public String getName() {
        if (node == null) {
            throw new InstanceNotInitializedException();
        }
        return node.name;
    }

    /**
     * 获取节点ID。
     * 
     * @return 节点ID。
     */
    public int getID() {
        if (node == null) {
            throw new InstanceNotInitializedException();
        }
        return node.cid;
    }

    /**
     * 返回指定的监控项。此处得到的监控项根据实现此方法的子类有将会有所不同。
     * {@link ConnectedNode}类会生成能够进行在线配置的Item，因为这些设置会直接发送
     * 给客户端进行配置。而{@link UnconnectedNode}生成的Item不支持在线配置。
     *
     * @param id 监控项ID。
     * @return 指定的监控项
     * @throws ItemNotExistsException
     */
    public abstract Item getItem(int id) throws ItemNotExistsException;

    /**
     * 返回所有监控项的列表。返回的具体实例见getItem方法的说明。
     *
     * @return 监控项列表。
     * @see #getItem(int)
     */
    public abstract List<Item> getAllItems();

    /**
     * 此抽象方法用于判定当前是否与客户端节点之间建立了连接。对于没有连接的客户端对象，
     * 则总是返回false。
     *
     * @return 若客户端已连接则true，否则false。
     * @see ConnectedNode#isConnected()
     * @see UnconnectedNode#isConnected()
     */
    public abstract boolean isConnected();
}
